﻿namespace FBlog.Core

open System

type IEnvironment = interface
    abstract CurrentUser : string
    abstract CurrentTime : DateTime
    end

type BlogPublishInfo(author : string, publishTime : DateTime) = class
    let _changeTime = ref publishTime

    member i.Author with get() = author
    member i.PublishTime with get() = publishTime
    member i.LastChangeTime with get() = !_changeTime and set(time) = _changeTime := time
    member p.IsEmpty with get() = author = "---"

    static member Empty = new BlogPublishInfo(author = "---", publishTime = DateTime.MinValue)
    end

type BlogPost(subject : string, rawBody : string, tags : string seq) = class

    let _publishInfo = ref BlogPublishInfo.Empty

    let setId,getId =
        let idLock = new obj()
        let _id = ref Guid.Empty
        let get() = lock (idLock) (fun () -> !_id)
        let set(id) = lock (idLock) (fun () -> _id := id )
        set, get

    member p.Id 
        with get() = getId()
        and set(id) = setId(id)

    member p.Subject with get() = subject
    member p.RawBody with get() = rawBody
    member p.Tags with get() = tags

    member p.PublishInfo
        with get() = !_publishInfo
        and set(publishInfoOpt) = _publishInfo := publishInfoOpt

    end

type IBlogPostRepository = interface
    inherit IDisposable
    abstract Load : Guid -> BlogPost option
    abstract Save : BlogPost -> unit
    end

type Blog(environment : IEnvironment, postRepository : IBlogPostRepository) = class

    let _postCount = ref 0

    let setNewId (post : BlogPost) = 
        post.Id <- Guid.NewGuid()

    let createNewPublishInfo() : BlogPublishInfo =
        new BlogPublishInfo(author = environment.CurrentUser, 
                            publishTime = environment.CurrentTime)

    let updatePublishInfo (info : BlogPublishInfo) =
        info.LastChangeTime <- environment.CurrentTime

    let updatePost (post : BlogPost) =
        match post.PublishInfo.IsEmpty with
        | true -> post.PublishInfo <- createNewPublishInfo()
        | false -> updatePublishInfo post.PublishInfo

    let savePost (post : BlogPost) =
        postRepository.Save(post)

    member b.Publish(post : BlogPost) = 
        incr _postCount
        post |> setNewId
        post |> updatePost
        post |> savePost

    member b.GetTotalPostCount() = !_postCount

    end